/*
 * @Author: Wangjun
 * @Date: 2023-03-21 09:12:52
 * @LastEditTime: 2024-06-05 09:59:01
 * @LastEditors: wangjun haodreams@163.com
 * @Description:
 * @FilePath: \aexp\expr.go
 * hnxr
 */
package aexp

import (
	"errors"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"sort"
	"strconv"
)

type Float64 float64

func (m Float64) String() string {
	return strconv.FormatFloat(float64(m), 'f', -1, 64)
}

func (m Float64) Eval() (any, error) {
	return float64(m), nil
}

type String string

func (m String) String() string {
	return string(m)
}

func (m String) Eval() (any, error) {
	return string(m), nil
}

func parse(ctx *Context, e ast.Expr) (eval Evaler, err error) {
	switch v := e.(type) {
	case *ast.Ident:
		i := new(Ident)
		i.name = v.Name
		i.ctx = ctx
		i.ctx.names = append(i.ctx.names, v.Name)
		return i, nil
	case *ast.BasicLit:
		if v.Kind == token.STRING {
			//删除第一个和最后一个引号
			return String(v.Value[1 : len(v.Value)-1]), nil
		}
		n, err := ParseNumber(v)
		if err != nil {
			return nil, err
		}
		return Float64(n), nil
	case *ast.ParenExpr: //() 括号运算
		parenExpr := new(ParenExpr)
		parenExpr.x, err = parse(ctx, v.X)
		if err != nil {
			return
		}
		return parenExpr, nil
	case *ast.BinaryExpr:
		binExpr := new(BinaryExpr)
		binExpr.x, err = parse(ctx, v.X)
		if err != nil {
			return
		}
		binExpr.y, err = parse(ctx, v.Y)
		if err != nil {
			return
		}

		binExpr.op = OP[v.Op]
		if binExpr.op == nil {
			err = errors.New("不支持的操作符:" + v.Op.String())
			return nil, err
		}
		return binExpr, nil
	case *ast.UnaryExpr:
		switch v.Op {
		case token.SUB:
			if t, ok := v.X.(*ast.BasicLit); ok {
				n, err := ParseNumber(t)
				if err != nil {
					return nil, err
				}
				n = -n
				return Float64(n), nil
			}
			ue := new(UnaryExpr)
			ue.x, err = parse(ctx, v.X)
			if err != nil {
				return nil, err
			}
			ue.op = neg
			return ue, nil
		case token.NOT:
			if t, ok := v.X.(*ast.BasicLit); ok {
				n, err := ParseNumber(t)
				if err != nil {
					return nil, err
				}
				if n == 0 {
					n = 1
				} else {
					n = 0
				}
				return Float64(n), nil
			}
			ue := new(UnaryExpr)
			ue.x, err = parse(ctx, v.X)
			if err != nil {
				return nil, err
			}
			ue.op = not
			return ue, nil
		}
	case *ast.CallExpr:
		ce := new(CallExpr)
		if t, ok := v.Fun.(*ast.Ident); ok {
			ce.name = t.Name
			f, ok := ctx.mapFunction[t.Name] //优先使用私有方法
			if ok {
				ce.method = f
			} else {
				f, ok = globalFunction[t.Name] //私有方法不存在时，使用全局方法
				if ok {
					ce.method = f
				} else {
					return nil, errors.New("不存在的函数:" + fmt.Sprint(t.Name))
				}
			}
		} else {
			return nil, errors.New("方法名称错误:" + fmt.Sprint(v))
		}
		ce.args = make([]Evaler, len(v.Args))
		for i, x := range v.Args {
			ce.args[i], err = parse(ctx, x)
			if err != nil {
				return nil, err
			}
		}
		ce.fvals = make([]any, len(v.Args))
		return ce, nil
	case *ast.SelectorExpr:
		name := parserSelectorExpr(v)
		i := new(Ident)
		i.name = name
		i.ctx = ctx
		i.ctx.names = append(i.ctx.names, name)
		return i, nil
	default:
		return nil, fmt.Errorf("解析失败[列:%d]", e.End()) // errors.New("解析失败:"+e.Pos())
	}
	return
}

// 解析a.b.c格式的内容
func parserSelectorExpr(e *ast.SelectorExpr) string {
	name := ""
	switch v := e.X.(type) {
	case *ast.SelectorExpr:
		name += parserSelectorExpr(v)
	case *ast.Ident:
		name += v.Name
	}
	if e.Sel != nil {
		name += "." + e.Sel.Name
	}

	return name
}

type Context struct {
	get         Get
	mapFunction map[string]Function //私有函数
	names       []string
}

type Expression struct {
	Name string
	eval Evaler
	err  error
	ctx  *Context
}

// New  get 如果没有用到变量可以传nil
func New(get Get) (e *Expression) {
	e = new(Expression)
	e.ctx = new(Context)
	e.ctx.get = get
	return e
}

func (m *Expression) SetFunc(get Get) {
	m.ctx.get = get
}

// 获取变量
func (m *Expression) String() string {
	return m.eval.String()
}

// 获取变量
func (m *Expression) Vars() []string {
	return m.ctx.names
}

// 注册一个私有方法
func (m *Expression) Parse(exp string) (err error) {
	expr, err := parser.ParseExpr(exp)
	if err != nil {
		m.err = err
		return
	}
	eval, err := parse(m.ctx, expr)
	if err != nil {
		m.err = err
		return
	}
	mapName := map[string]bool{}
	for _, name := range m.ctx.names {
		_, ok := mapName[name]
		if ok {
			continue
		}
		mapName[name] = true
	}

	idx := 0
	for name := range mapName {
		m.ctx.names[idx] = name
		idx++
	}

	m.ctx.names = m.ctx.names[:idx]
	sort.Strings(m.ctx.names)
	m.eval = eval
	return
}

// 注册一个私有函数
func (m *Expression) RegisterMethod(name string, f Function) {
	if m.ctx.mapFunction == nil {
		m.ctx.mapFunction = make(map[string]Function)
	}
	m.ctx.mapFunction[name] = f
}

func (m *Expression) Eval() (any, error) {
	return m.eval.Eval()
}

func (m *Expression) Evaluate(get Get) (any, error) {
	m.ctx.get = get
	return m.eval.Eval()
} //

// get 如果没有用到变量可以传nil
func Parse(exp string, get Get) (e *Expression, err error) {
	e = New(get)
	err = e.Parse(exp)
	return
}

func NewMethod(m map[string]any) Get {
	return func(name string) (any, error) {
		v, ok := m[name]
		if ok {
			return v, nil
		}
		return nil, errors.New("没有这个变量" + name)
	}
}
